/*
Autor: Alexander Savochkin, 2010
New BSD License
*/

#include "SerialIO.h"
#include "IoServiceSource.h"
#include "Exception.h"

#include <boost/utility/in_place_factory.hpp>
#include <boost/optional.hpp>
#include <boost/none.hpp>
#include <boost/lexical_cast.hpp>

using boost::asio::serial_port;

namespace SRCLF 
{
namespace IO
{
namespace Serial
{
	//See example:
	//http://old.nabble.com/Simple-serial-port-demonstration-with-boost-asio-asynchronous-I-O-td19849520.html 

	const char* SerialPort::file_name_key = "file_name";
	const char* SerialPort::baud_rate_key = "baud_rate";
	const char* SerialPort::character_size_key = "character_size";
	const char* SerialPort::parity_key = "parity";
	const char* SerialPort::flow_control_key = "flow";

	SerialPort::~SerialPort()
	{
		//close serial connection
	}

	SerialPort::SerialPort(const Section &config_section) :
		serial_port(getCommonIOService())	
	{
		//Serial port filename
		string serial_port_file_name = config_section.getScalarByKey(file_name_key);
			//throw... "Serial port file name is mandatory parameter: section name" + config_section.name ); 	

		//baud rate
		unsigned baud_rate = boost::lexical_cast<unsigned>(config_section.getScalarByKey(baud_rate_key));

		//character size
		unsigned params_search_it = boost::lexical_cast<unsigned>(config_section.getScalarByKey(character_size_key));

		//parity
		string sval = config_section.getScalarByKey(parity_key);
		serial_port::parity::type parity;
		if (sval == "n" || sval == "none")
			parity = boost::asio::serial_port_base::parity::none;
		else if (sval == "o" || sval == "odd")
			parity = boost::asio::serial_port_base::parity::odd;
		else if (sval == "e" || sval == "even")
			parity = boost::asio::serial_port_base::parity::even;
		else
			throw  ConfigException( "Can't recognize serial port parity setting value: " + sval );


		//flow control
		sval = config_section.getScalarByKey(flow_control_key);
		serial_port::flow_control::type flow;
		if (sval == "n" || sval == "none")
			flow = boost::asio::serial_port_base::flow_control::none;
		else if (sval == "software")
			flow = boost::asio::serial_port_base::flow_control::software;
		else if (sval == "hardware")
			flow = boost::asio::serial_port_base::flow_control::hardware;
		else
			throw  ConfigException( "Can't recognize serial port flow control setting value: " + sval );
	}


	AbstractSerialInput::AbstractSerialInput(const string& name, const Configuration& config)
	{
		const Section& config_section = config.getSection(Section::input, name);
		serial_port = boost::in_place(config_section);
	}

	AbstractSerialInput::~AbstractSerialInput() {}

	bool AbstractSerialInput::open() 
	{
		return true;
	}

	void AbstractSerialInput::close() {}

	AbstractSerialOutput::AbstractSerialOutput(const string& name, const Configuration& config)
	{
		const Section& config_section = config.getSection(Section::output, name);
		serial_port = boost::in_place(config_section);
	}

	AbstractSerialOutput::~AbstractSerialOutput() {}

	bool AbstractSerialOutput::open() 
	{
		return true;
	}

	void AbstractSerialOutput::close() {}
} //namespace Serial
} //namespace IO
} //namespace SRCLF